package model

import (
	"reflect"
	"strings"
	"unicode"
)

type TableName interface {
	TableName() string
}

type field struct {
	FieldName string
	Typ       reflect.Type
	ColName   string
	Offset    uintptr
}

// Model 维护结构体和数据库字段间的映射
type Model struct {
	TableName     string
	ColToFieldMap map[string]field
	FieldToColMap map[string]field

	// 分库分表主键
	ShardingKeys map[string]string
	ShardingFunc ShardingFunc
}

type Dst struct {
	DbName    string
	TableName string
}

type ShardingFunc interface {
	AllNodes() []*Dst
	Sharding(val any) (*Dst, error)
}

// 不支持泛型，因为ShardingFunc在Model中使用，Model初始化时不支持
//type ShardingType interface {
//	~int | ~int8 | ~int16 | ~int32 | ~int64
//}
//
//type ShardingFunc[T ShardingType] interface {
//	AllNodes() []*Dst
//	Sharding(val T) (*Dst, error)
//}

func (m *Model) SetSharding(ShardingKeys map[string]string, shardingFunc ShardingFunc) *Model {
	m.ShardingKeys = ShardingKeys
	m.ShardingFunc = shardingFunc
	return m
}

func (m *Model) parseModel(t any) {
	typ := reflect.TypeOf(t)
	if typ.Kind() != reflect.Ptr {
		panic("model must be a pointer")
	}
	typ = typ.Elem()

	tableName, ok := t.(TableName)
	if !ok {
		m.TableName = underlineCase(typ.Name())
	} else {
		m.TableName = tableName.TableName()
	}

	m.ColToFieldMap = map[string]field{}
	m.FieldToColMap = map[string]field{}
	for i := 0; i < typ.NumField(); i++ {
		fd := typ.Field(i)
		tag := fd.Tag.Get("orm")
		if tag == "" {
			tag = underlineCase(fd.Name)
		}
		f := field{
			FieldName: tag, // 数据库字段
			Typ:       fd.Type,
			ColName:   fd.Name, // 元字段
			Offset:    fd.Offset,
		}
		m.ColToFieldMap[f.ColName] = f
		m.FieldToColMap[tag] = f
	}
}

func underlineCase(s string) string {
	builder := strings.Builder{}
	for i, v := range s {
		if unicode.IsUpper(v) {
			if i > 0 {
				builder.WriteString("_")
			}

			builder.WriteRune(unicode.ToLower(v))
		} else {
			builder.WriteRune(v)
		}
	}
	return builder.String()
}
